<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: 凡星
// +----------------------------------------------------------------------
namespace Admin\Controller;

/**
 * 在线升级控制器
 */
class UpdateController extends AdminController
{
    public function index()
    {
        // 一键升级功能的目录可写权限判断
        $dirList = array(
            'Addons',
            'Application',
            'Public',
            'ThinkPHP',
            'URLRewrite',
            'Uploads'
        );
        $noWritable = array();
        foreach ($dirList as $dir) {
            $dirPath = SITE_PATH . '/' . $dir;
            if (is_dir($dirPath) && !is_writable($dirPath)) {
                $noWritable [] = $dir;
            }
        }
        $this->assign('noWritable', $noWritable);

        $this->display();
    }

    function deal_sql()
    {
        define ('IN_WEIPHP_ADMIN', true);
        $path = SITE_PATH . '/update_db_tool.php';
        if (!file_exists($path)) {
            $this->error('升级文件不存在，请先把升级文件update_db_tool.php放置在  ' . SITE_PATH . ' 目录下');
        }

        require_once $path;
    }

    function getRemoteVersion()
    {
        // cookie ( 'cookie_close_version', 0 );
        $remote = 'http://www.weiphp.cn/index.php?s=/home/index/update_version';
        $new_version = wp_file_get_contents($remote);
        $res = $new_version > C('SYSTEM_UPDATRE_VERSION') && cookie('cookie_close_version') != $new_version;
        echo $res ? $new_version : 0;
    }

    // 获取关闭升级提醒
    public function set_cookie_close_version()
    {
        $cookie_close_version = intval($_GET ['cookie_close_version']);
        cookie('cookie_close_version', $cookie_close_version);
    }

    // 清空缓存
    function delcache()
    {
        $cahce_dirs = RUNTIME_PATH;
        $this->rmdirr($cahce_dirs);

        @mkdir($cahce_dirs, 0777, true);
        $this->display();
    }

    function rmdirr($dirname)
    {
        if (!file_exists($dirname)) {
            return false;
        }
        if (is_file($dirname) || is_link($dirname)) {
            return unlink($dirname);
        }
        $dir = dir($dirname);
        if ($dir) {
            while (false !== $entry = $dir->read()) {
                if ($entry == '.' || $entry == '..') {
                    continue;
                }
                $this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
            }
        }
        $dir->close();
        return rmdir($dirname);
    }

    // =========================一键升级功能==========================================
    var $updateURL;
    var $remoteBaseURL;

    function _initialize()
    {
        parent::_initialize();
        set_time_limit(0);

        $this->remoteBaseURL = 'http://www.weiphp.cn'; // TODO

        $this->updateURL = $this->remoteBaseURL . '/index.php?s=/home/index/update_json&version=' . intval(C('SYSTEM_UPDATRE_VERSION'));
    }

    // 查询是否有更新版本
    function step01_checkVersionByAjax()
    {
        // 获取官方升级信息
        $url = $this->remoteBaseURL . '/index.php?s=/home/index/update_json&version=' . intval(C('SYSTEM_UPDATRE_VERSION'));

        $list = wp_file_get_contents($url);
        $list = json_decode($list, true);
        $this->assign('_list', $list);

        S('update_version_lists', $list);

        $this->display();
    }

    // 下载更新包
    function step02_download()
    {
        header("content-Type: text/html; charset=utf-8");

        $version = I('post.version');

        Vendor('Update');
        $updateClass = new \Update ();

        $packageURL = $this->remoteBaseURL . '/index.php?s=/home/index/download_update_package.html&version=' . $version;

        echo $updateClass->downloadFile($packageURL);
    }

    // 解压更新包
    function step03_unzipPackage()
    {
        Vendor('Update');
        $updateClass = new \Update ();

        $version = I('version');
        echo $updateClass->unzipPackage($version);
    }

    // 检查要覆盖的文件的可写权限和md5码
    function step04_checkFileIsWritable()
    {
        $list = $this->_checkFileIsWritable();
        if (empty ($list)) {
            echo 1;
            exit ();
        }

        // 删除更新锁
        $version = I('version');
        $lockName = DATA_PATH . '/update/' . str_replace('.zip', '.lock', $version);
        unlink($lockName);

        $this->assign('list', $list);
        $this->display();
    }

    // 关闭站点，并设置关闭原因
    function closeSite()
    {
        $data = model('Xdata')->get('admin_Config:site');

        $config ['site_closed'] = $data ['site_closed'];
        $config ['site_closed_reason'] = $data ['site_closed_reason'];

        // 保存当前站点的配置关闭原因
        F('site_config', $config, DATA_PATH . '/update');

        $data ['site_closed'] = 0;
        $data ['site_closed_reason'] = '站点升级中...请稍后再访问。';

        model('Xdata')->put('admin_Config:site', $data);
    }

    // 恢复升级前的站点配置
    function openSite()
    {
        $config = F('site_config', '', DATA_PATH . '/update');
        if (empty ($config)) {
            return false;
        }

        $data = model('Xdata')->get('admin_Config:site');
        $data ['site_closed'] = $config ['site_closed'];
        $data ['site_closed_reason'] = $config ['site_closed_reason'];

        model('Xdata')->put('admin_Config:site', $data);
    }

    // 清除文件缓存
    function cleanCache()
    {
        $this->_rmdirr(CORE_RUN_PATH . '/');
    }

    // 自动更新数据库
    function step07_dealSQL()
    {
        // $this->closeSite();
        $filePath = $targetDir = DATA_PATH . '/update/download/unzip/updateDB.php';
        if (!file_exists($filePath)) { // 如果本次升级没有数据库的更新，直接返回
            echo 1;
            exit ();
        }

        require_once($filePath);
        updateDB();
        unlink($filePath);

        // 数据库验证
        $filePath = $targetDir = DATA_PATH . '/update/download/unzip/checkDB.php';
        if (!file_exists($filePath)) { // 如果本次升级没有数据库的更新后的验证代码，直接返回
            echo 1;
            exit ();
        }

        require_once($filePath);
        // checkDB方法正常返回1 否则返回异常的说明信息，如：ts_xxx数据表创建不成功
        checkDB();

        unlink($filePath);
        echo 1;
    }

    // 递归检查文件的可写权限和md5
    private function _checkFileIsWritable($source = '', $res = array())
    {
        if (empty ($source))
            $source = DATA_PATH . '/update/download/unzip';

        $handle = dir($source);
        while ($entry = $handle->read()) {
            if (($entry != ".") && ($entry != "..")) {
                $file = $source . "/" . $entry;
                if (is_dir($file)) {
                    $res = $this->_checkFileIsWritable($file, $res);
                } else {
                    // 检查可写权限
                    if (!is_writable($file)) {
                        $res [] = $file;
                    }
                    // 检查文件md5
                }
            }
        }

        return $res;
    }

    // 自动覆盖文件
    function step06_overWritten()
    {
        // 提示需要删除的文件
        $filePath = $targetDir = DATA_PATH . '/update/download/unzip/fileForDeleteList.php';
        if (file_exists($filePath)) {
            $deleteList = require_once($filePath);
            foreach ($deleteList as $d) {
                unlink(SITE_PATH . '/' . $d);
            }
            unlink($filePath);
        }

        // 执行文件替换
        tsload(ADDON_PATH . '/library/Update.class.php');
        $updateClass = new Update ();
        $res = $updateClass->overWrittenFile();
        if (!empty ($res ['error'])) {
            $this->assign('error', $res ['error']);
            $this->display();
        } else {
            echo 1;
        }
    }

    function step08_finishUpate()
    {
        // 清除缓存
        $this->cleanCache();

        // 开启站点
        $this->openSite();

        // 更新本地版本号信息
        $this->_updateFinishVersionStatus();

        // 如果是一键升级的话
        if ($_SESSION ['admin_update_upateAll'] == true) {
            echo 1;
        } else {
            echo 0;
        }
    }

    // 写入当前版本信息
    private function _writeVersion($key, $arr)
    {
        $path = DATA_PATH . '/update';
        $arr ['status'] = 0; // 未升级状态

        $versionArr = $this->_getVersionInfo($path);
        $versionArr [$key] = $arr;

        F('versions', $versionArr, $path);

        return $versionArr;
    }

    private function _updateVersionStatus($key)
    {
        $path = DATA_PATH . '/update';
        $versionArr = $this->_getVersionInfo($path);

        foreach ($versionArr as $k => &$vo) {
            if ($k != $key)
                continue;

            $vo ['status'] = 1; // 升级中的状态
        }

        F('versions', $versionArr, $path);
    }

    private function _updateFinishVersionStatus()
    {
        $path = DATA_PATH . '/update';
        $versionArr = $this->_getVersionInfo($path);

        foreach ($versionArr as $k => &$vo) {
            if ($vo ['status'] != 1)
                continue;

            $vo ['status'] = 2; // 升级完成的状态
        }

        F('versions', $versionArr, $path);
    }

    private function _getVersionInfo($path)
    {
        $file = $path . '/versions.php';

        $versionArr = array();
        if (file_exists($file)) {
            $versionArr = F('versions', '', $path);
        }

        return $versionArr;
    }

    private function _rmdirr($dirname)
    {
        if (!file_exists($dirname)) {
            return false;
        }
        if (is_file($dirname) || is_link($dirname)) {
            return unlink($dirname);
        }
        $dir = dir($dirname);
        if ($dir) {
            while (false !== $entry = $dir->read()) {
                if ($entry == '.' || $entry == '..') {
                    continue;
                }
                $this->_rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
            }
        }
        $dir->close();
        return rmdir($dirname);
    }

    private function _createtable($sql, $db_charset)
    {
        $db_charset = (strpos($db_charset, '-') === FALSE) ? $db_charset : str_replace('-', '', $db_charset);
        $type = strtoupper(preg_replace("/^\s*CREATE TABLE\s+.+\s+\(.+?\).*(ENGINE|TYPE)\s*=\s*([a-z]+?).*$/isU", "\\2", $sql));
        $type = in_array($type, array(
            "MYISAM",
            "HEAP"
        )) ? $type : "MYISAM";
        return preg_replace("/^\s*(CREATE TABLE\s+.+\s+\(.+?\)).*$/isU", "\\1", $sql) . (mysql_get_server_info() > "4.1" ? " ENGINE=$type DEFAULT CHARSET=$db_charset" : " TYPE=$type");
    }

    private function _updataStorey()
    {
        $map ['data'] = array(
            'neq',
            'N;'
        );
        $commentlist = D('comment')->where($map)->findAll();
        foreach ($commentlist as $v) {
            $data = unserialize($v ['data']);
            if ($data ['storey']) {
                D('comment')->where('comment_id=' . $v ['comment_id'])->setField('storey', $data ['storey']);
            }
        }
    }

    function md5File()
    {
        ini_set();
        $res = $this->_md5File();
    }

    private function _md5File($source = '.', $res = array())
    {
        $handle = dir($source);

        while ($entry = $handle->read()) {
            if (($entry != ".") && ($entry != "..")) {
                $file = $source . "/" . $entry;
                if (is_dir($file)) {
                    $this->_md5File($file, $res);
                } else {
                    $data ['version'] = 221301;
                    $data ['file'] = str_replace('./', '', $file);
                    $data ['md5'] = md5_file($file);
                    M('file_version')->add($data);
                }
            }
        }

        return $res;
    }

    /**
     * 本地一键安装接口
     *
     * @return void
     */
    public function downloadAndInstall()
    {
        header("content-Type: text/html; charset=utf-8");
        // 获取下载地址
        $id = intval($_GET ['id']);
        $url = $this->remoteBaseURL . '/index.php?s=admin/store/downloadApp&id=' . $id;
// 		dump($url);exit;
        $info = wp_file_get_contents($url);
        $info = json_decode($info, true);
        if (!$info ['status']) {
            $this->error($info ['error']);
            exit ();
        }

        // 载入下载类
        Vendor('Update');
        $updateClass = new \Update ();
        // 从服务器端下载应用到本地
        $res = $updateClass->downloadFile($info ['data'] ['packageURL']);
        if ($res != 1) {
            $this->error('下载应用失败，请确认网络是否正常');
            exit ();
        }

        // 压缩
        $package = explode('/', $info ['data'] ['packageURL']);
        $packageName = array_pop($package);
        $targetDir = $updateClass->downloadPath . 'unzip';

        // 创建目录unzip
        if (!is_dir($targetDir)) {
            @mkdir($targetDir, 0777);
        }
        $res = $updateClass->unzipPackage($packageName, $targetDir);
        if ($res != 1) {
            $this->error('下载应用解压失败');
            exit ();
        }

        // 覆盖代码
        switch ($info ['data'] ['type']) {
            case 3 :
                // 万能页面功能块
                $res = $updateClass->overWrittenFile(SITE_PATH . '/Addons/Diy/Widget');
                break;
            case 2 :
                // 在线素材
                $res = $updateClass->overWrittenFile(SITE_PATH . '/Addons/Material');
                break;
            case 2 :
                // 微官网模板
                $res = $updateClass->overWrittenFile(SITE_PATH . '/Addons/WeiSite/View/default');
                break;
            default :
                // 微信插件
                $res = $updateClass->overWrittenFile(SITE_PATH . '/Addons');
                if (empty ($res)) {
                    $this->install($updateClass->addon_name);
                    exit ();
                }
        }
        $this->success('安装完成');
    }

    /**
     * 自动安装插件
     */
    public function install($addon_name)
    {
        $class = get_addon_class($addon_name);
        if (!class_exists($class))
            $this->error('插件不存在');
        $addons = new $class ();
        $info = $addons->info;
        if (!$info || !$addons->checkInfo()) // 检测信息的正确性
            $this->error('插件信息缺失');
        session('addons_install_error', null);
        $install_flag = $addons->install();
        if (!$install_flag) {
            $this->error('执行插件预安装操作失败' . session('addons_install_error'));
        }
        $addonsModel = D('Addons');
        $data = $addonsModel->create($info);
        if (!$data)
            $this->error($addonsModel->getError());

        // isset($data['has_adminlist']) || $data['has_adminlist'] = intval(is_array($addons->admin_list) && $addons->admin_list !== array());
        isset ($data ['type']) || $data ['type'] = intval(file_exists(ONETHINK_ADDON_PATH . $data ['name'] . '/Model/WeixinAddonModel.class.php'));

        if ($addonsModel->add($data)) {
            $config = array(
                'config' => json_encode($addons->getConfig())
            );
            $addonsModel->where("name='{$addon_name}'")->save($config);
            $hooks_update = D('Hooks')->updateHooks($addon_name);
            if ($hooks_update) {
                S('hooks', null);
                $this->success('安装成功');
            } else {
                $addonsModel->where("name='{$addon_name}'")->delete();
                $this->error('更新钩子处插件失败,请卸载后尝试重新安装');
            }
        } else {
            $this->error('写入插件数据失败');
        }
    }

    // 更新本地的授权信息
    function save_store_license()
    {
        $config_map ['name'] = 'WEIPHP_STORE_LICENSE';
        $res = M('config')->where($config_map)->setField('value', I('license'));
        //dump($res);
        //lastsql();
    }
}
